Skip to content

Comments

Add analyzer redirecting API#74820

Merged
jjonescz merged 21 commits intodotnet:mainfrom
jjonescz:analyzer-resolver-api
Feb 12, 2025
Merged

Add analyzer redirecting API#74820
jjonescz merged 21 commits intodotnet:mainfrom
jjonescz:analyzer-resolver-api

Conversation

@jjonescz
Copy link
Member

@jjonescz jjonescz commented Aug 20, 2024

@ghost ghost added Area-Analyzers untriaged Issues and PRs which have not yet been triaged by a lead labels Aug 20, 2024
@dotnet-policy-service dotnet-policy-service bot added the Needs API Review Needs to be reviewed by the API review council label Aug 20, 2024
@jjonescz jjonescz removed the VSCode label Aug 27, 2024
@jjonescz jjonescz marked this pull request as ready for review August 29, 2024 16:32
@jjonescz jjonescz requested review from a team as code owners August 29, 2024 16:32
@jjonescz jjonescz changed the title Add IAnalyzerAssemblyResolver public API Add analyzer redirecting public API Aug 30, 2024
@RikkiGibson RikkiGibson self-assigned this Jan 13, 2025
@333fred
Copy link
Member

333fred commented Jan 21, 2025

@RikkiGibson @jaredpar for reviews

namespace Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting;

/// <summary>
/// Any MEF component implementing this interface will be used to redirect analyzer assemblies.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a bit here that drives home this happens before shadow copy? Essentially this redirects the path that we pass to the compiler and the compiler will then do as it normally does with the path?

@jaredpar
Copy link
Member

@dotnet/roslyn-ide, @jasonmalinowski PTAL

@jasonmalinowski jasonmalinowski self-requested a review January 24, 2025 19:02
@jjonescz
Copy link
Member Author

@jasonmalinowski for a review, thanks

@jaredpar
Copy link
Member

@jasonmalinowski PTAL

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments. The code itself is fine, but after the discussion I had with @jaredpar I'm not entirely convinced this can be implemented as the interface is currently structured given some of the async requirements that exist in VS and the stronger requirements that exist in Roslyn. Do we already have an implementation of this that I could look at?

/// or <see langword="null"/> if this instance cannot redirect the given assembly.
/// </returns>
/// <remarks>
/// If two redirects return different paths for the same assembly, no redirection will be performed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// If two redirects return different paths for the same assembly, no redirection will be performed.
/// If two redirectors return different paths for the same assembly, no redirection will be performed.


private string? TryRedirectAnalyzerAssembly(string fullPath)
{
if (!_hostInfo.AnalyzerAssemblyRedirectors.IsDefaultOrEmpty)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is strictly necessary -- the foreach will bail quite quickly if this is the case...

}
}
}
catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Diagnostic))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Diagnostic))
catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.General))

Or maybe even critical. Because if a redirector is throwing exceptions, then we're likely loading mismatched binaries and the product might be broken anyways.

return GetMappedRazorSourceGenerator(fullPath);
}

if (TryRedirectAnalyzerAssembly(fullPath) is { } redirectedPath)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If @jaredpar's work doesn't come first, we should then refactor this method away by converting the IsSdkRazorSourceGenerator/GetMappedRazorSourceGenerator methods into a redirector.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think Jared's work is going to refactor all this and we just want to get this in so we can continue on the SDK side etc.

<RestrictedInternalsVisibleTo Include="Microsoft.VisualStudio.IntelliCode" Partner="Pythia" Key="$(IntelliCodeKey)" />
<RestrictedInternalsVisibleTo Include="Microsoft.VisualStudio.IntelliCode.CSharp" Partner="Pythia" Key="$(IntelliCodeCSharpKey)" />
<RestrictedInternalsVisibleTo Include="Microsoft.VisualStudio.IntelliCode.CSharp.Extraction" Partner="Pythia" Key="$(IntelliCodeCSharpKey)" />
<RestrictedInternalsVisibleTo Include="Microsoft.Net.Sdk.AnalyzerRedirecting" Namespace="Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be 100% clear here, this Microsoft.Net.Sdk.AnalyzerRedirecting assembly is something that ships with VS, and is versioned with VS, and does not ship inside the .NET SDK?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is built and versioned from the .NET SDK repo, then inserted into VS and shipped with VS.

/// <remarks>
/// If two redirects return different paths for the same assembly, no redirection will be performed.
/// </remarks>
string? RedirectPath(string fullPath);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this ever need to be async? Or is the assumption that any async would be to create the redirector in the first place?

Copy link
Member Author

@jjonescz jjonescz Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't thought about that. Currently, no async is needed. When we need async during creation or redirecting, we can update the code, I think. We have just one implementation and don't expect to have more for now.

namespace Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting;

/// <summary>
/// Any MEF component implementing this interface will be used to redirect analyzer assemblies.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have a comment explicitly stating what threading expectations exist here. Since it's not async that means no thread switching would be allowed. (And if it was async, it might still require the stronger guarantee that no thread switching is allowed.)

Per the conversation I had with @jaredpar earlier today, I'm not entirely convinced this interface could actually be implemented safely, especially if to actually implement it you need to fetch any VS service, which would require asynchrony.

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Digging further I found dotnet/sdk#42861 as the implementation, which answered a few of my questions. So that works fine because the implementation isn't needing to grab any VS services. (And it's doing so by looking at AppDomain.CurrentDomain.BasePath which seems...highly suspect long term) So although this works fine for that implementation I'm not sure any other implementations would be able to use this, and I don't think we could migrate the Razor code over to use this if we wanted to without having to revise the API shape.

@jaredpar given you had some other refactorings coming, thoughts on this?

@jjonescz
Copy link
Member Author

jjonescz commented Feb 6, 2025

And it's doing so by looking at AppDomain.CurrentDomain.BasePath which seems...highly suspect long term

Hm, I just need to find path to VS (because that's where the runtime analyzers are deployed and we want to redirect to them). Is there a better way?

So although this works fine for that implementation I'm not sure any other implementations would be able to use this

I don't think it's the plan to have more implementations, this is merely a hook for the SDK.

@jjonescz jjonescz merged commit 3f2e5e2 into dotnet:main Feb 12, 2025
28 checks passed
@jjonescz jjonescz deleted the analyzer-resolver-api branch February 12, 2025 09:33
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Feb 12, 2025
@akhera99 akhera99 modified the milestones: Next, 17.14 P2 Feb 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Analyzers Needs API Review Needs to be reviewed by the API review council untriaged Issues and PRs which have not yet been triaged by a lead VSCode

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants